﻿Imports System.ComponentModel
Imports LSW.WP8.Extension
Imports System.Diagnostics

Namespace Controls
    Public Class PowerListBox
        Inherits ListBox

        Dim dic As New Dictionary(Of Double, Border)
        Dim _scrollView As ScrollViewer
        Dim _isScrolling As Boolean

        Public Sub New()
            DefaultStyleKey = GetType(PowerListBox)
        End Sub

        Private Sub PowerListBox_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
            If DesignerProperties.GetIsInDesignMode(Me) Then
                Return
            End If
            ApplyTemplate()
            _scrollView.ScrollToVerticalOffset(_scrollView.VerticalOffset)

            Dim b = _scrollView.Descendants(Of Border).FirstOrDefault
            Debug.Assert(b IsNot Nothing)
            Dim vsGroup = b.GetVisualStateGroup("ScrollStates", True)
            Debug.Assert(vsGroup IsNot Nothing)
            AddHandler vsGroup.CurrentStateChanging, AddressOf vsGroup_CurrentStateChanging

            If ItemsRootPanel IsNot Nothing AndAlso ItemsRootPanel.Children IsNot Nothing Then
                Dim height_sum As Double = 0
                dic.Clear()
                For i = 0 To ItemsRootPanel.Children.Count - 1
                    Dim fe = DirectCast(VisualTreeHelper.GetChild(ItemsRootPanel.Children(i), 0), Border)
                    dic.Add(height_sum, fe)

                    If height_sum <= DirectCast(ItemsRootPanel, WaterFallPanel).GetItemHeight(i) Then
                        height_sum = DirectCast(ItemsRootPanel, WaterFallPanel).GetItemHeight(i) + 1
                    Else
                        height_sum = DirectCast(ItemsRootPanel, WaterFallPanel).GetItemHeight(i)
                    End If

                    fe.Height = fe.ActualHeight
                Next
            End If
        End Sub

        Private Sub vsGroup_CurrentStateChanging(sender As Object, e As VisualStateChangedEventArgs)
            If e.NewState.Name = "NotScrolling" Then
                _isScrolling = False
                RemoveHandler CompositionTarget.Rendering, AddressOf CompositionTarget_Rendering
            Else
                _isScrolling = True
                AddHandler CompositionTarget.Rendering, AddressOf CompositionTarget_Rendering
            End If
        End Sub

        Private _itemsPresenter As ItemsPresenter
        Private ReadOnly Property ItemsPresenter() As ItemsPresenter
            Get
                Return If(_itemsPresenter, (_itemsPresenter.InlineAssignHelper(_scrollView.Descendants(Of ItemsPresenter).FirstOrDefault)))
            End Get
        End Property

        Private _itemsRootPanel As Panel
        Private ReadOnly Property ItemsRootPanel() As Panel
            Get
                If _itemsRootPanel Is Nothing AndAlso ItemsPresenter IsNot Nothing Then
                    _itemsRootPanel = DirectCast(ItemsPresenter.ChildrenEx().FirstOrDefault, Panel)
                End If
                Return _itemsRootPanel
            End Get
        End Property

        Private Sub PowerListBox_Unloaded(sender As Object, e As RoutedEventArgs) Handles Me.Unloaded
            Dim b = _scrollView.Descendants(Of Border).FirstOrDefault
            Debug.Assert(b IsNot Nothing)
            Dim vsGroup = b.GetVisualStateGroup("ScrollStates", True)
            Debug.Assert(vsGroup IsNot Nothing)
            RemoveHandler vsGroup.CurrentStateChanging, AddressOf vsGroup_CurrentStateChanging
        End Sub

        Public Overrides Sub OnApplyTemplate()
            MyBase.OnApplyTemplate()
            _scrollView = GetTemplateChild("ScrollViewer")
            Debug.Assert(_scrollView IsNot Nothing)
        End Sub

        Private Sub CompositionTarget_Rendering(sender As Object, e As EventArgs)
            RefreshDisplayArea()
        End Sub

        Private Sub RefreshDisplayArea()
            For i = 0 To ItemsRootPanel.Children.Count - 1
                Dim item = GetItem(i)
                Dim fe = DirectCast(VisualTreeHelper.GetChild(item, 0), Border)
                fe.Height = fe.ActualHeight

                Dim height = DirectCast(ItemsRootPanel, WaterFallPanel).GetItemHeight(i)
                If (_scrollView.VerticalOffset - fe.Height) > height OrElse height > (_scrollView.VerticalOffset + 820) Then
                    fe.Child.Visibility = Visibility.Collapsed
                Else
                    fe.Child.Visibility = Visibility.Visible
                End If
            Next
        End Sub

        Private Function GetItem(index As Integer) As ListBoxItem
            If index < 0 OrElse index >= Items.Count Then
                Return Nothing
            End If
            If ItemsSource IsNot Nothing Then
                Dim isVirtualizing = VirtualizingStackPanel.GetIsVirtualizing(Me)
                If Not isVirtualizing Then
                    Debug.Assert(ItemsRootPanel IsNot Nothing)
                    Return DirectCast(ItemsRootPanel.Children(index), ListBoxItem)
                End If
                Debug.Assert(ItemContainerGenerator IsNot Nothing)
                Return DirectCast(ItemContainerGenerator.ContainerFromIndex(index), ListBoxItem)
            End If
            Return DirectCast(Items(index), ListBoxItem)
        End Function

#Region "FirstVisibleIndex"
        Public Shared ReadOnly FirstVisibleIndexProperty As DependencyProperty = DependencyProperty.Register("FirstVisibleIndex", GetType(Integer), GetType(PowerListBox), New PropertyMetadata(0))

        Public Property FirstVisibleIndex() As Integer
            Get
                Return CInt(GetValue(FirstVisibleIndexProperty))
            End Get
            Private Set(value As Integer)
                SetValue(FirstVisibleIndexProperty, value)
            End Set
        End Property
#End Region

#Region "LastVisibleIndex"
        Public Shared ReadOnly LastVisibleIndexProperty As DependencyProperty = DependencyProperty.Register("LastVisibleIndex", GetType(Integer), GetType(PowerListBox), New PropertyMetadata(0))

        Public Property LastVisibleIndex() As Integer
            Get
                Return CInt(GetValue(LastVisibleIndexProperty))
            End Get
            Private Set(value As Integer)
                SetValue(LastVisibleIndexProperty, value)
            End Set
        End Property
#End Region
    End Class
End Namespace